﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Caliburn.Micro;
using MediaOwl.Common;
using MediaOwl.Common.Messages;
using MediaOwl.Common.ScreenManagement;
using MediaOwl.Common.ViewModels;
using MediaOwl.WebSearch.BingService;
using MediaOwl.WebSearch.Data;
using MediaOwl.WebSearch.Resources;

namespace MediaOwl.WebSearch.ViewModels
{
    [Export(typeof(IWorkitem<WebSearchViewModel>))]
    public sealed class BingImageSearchViewModel : Workitem<WebSearchViewModel>
    {
        #region Fields
        private readonly IEventAggregator eventAggregator;
        #endregion
        
        #region Constructor
        [ImportingConstructor]
        public BingImageSearchViewModel(IEventAggregator eventAggregator)
        {
            this.eventAggregator = eventAggregator;
            DisplayName = Captions.BingImageSearchTitle;
            IsHomeScreen = true;
            Order = 2;

            Offset = 0;
            Results = new BindableCollection<ImageResult>();
            ItemsPerPage = 20;

            Sizes = ImageFilters.Sizes;
            Aspects = ImageFilters.Aspects;
            Colors = ImageFilters.Colors;
            Styles = ImageFilters.Styles;
            Faces = ImageFilters.Faces;
            SelectedAspect = ImageFilters.All;
            SelectedColor = ImageFilters.All;
            SelectedFace = ImageFilters.All;
            SelectedSize = ImageFilters.All;
            SelectedStyle = ImageFilters.All;
        }

        #endregion

        #region Properties with Backing-Fields

        private BindableCollection<ImageResult> results;
        public BindableCollection<ImageResult> Results
        {
            get { return results; }
            set { results = value; NotifyOfPropertyChange(() => Results); }
        }

        private ImageResult selectedItem;
        public ImageResult SelectedItem
        {
            get { return selectedItem; }
            set
            {
                selectedItem = value;
                NotifyOfPropertyChange(() => SelectedItem);
            }
        }

        private string searchText;
        public string SearchText
        {
            get { return searchText; }
            set
            {
                searchText = value;
                NotifyOfPropertyChange(() => SearchText);
                NotifyOfPropertyChange(() => CanSearchItems);
            }
        }

        public bool CanSearchItems
        {
            get
            {
                if (string.IsNullOrEmpty(SearchText))
                {
                    return false;
                }
                return true;
            }
        }

        public bool CanPrevious
        {
            get
            {
                return Offset > 0;
            }
        }

        public bool CanNext
        {
            get
            {
                return Offset + ItemsPerPage < TotalResults;
            }
        }

        private uint itemsPerPage;
        public uint ItemsPerPage
        {
            get
            {
                return itemsPerPage;
            }
            set
            {
                if (itemsPerPage == value)
                    return;
                itemsPerPage = value;
                NotifyOfPropertyChange(() => ItemsPerPage);
                NotifyOfPropertyChange(() => CanNext);
            }
        }

        private uint currentPage;
        public uint CurrentPage
        {
            get { return currentPage; }
            set
            {
                if (value == currentPage)
                    return;
                currentPage = value;
                NotifyOfPropertyChange(() => CurrentPage);
                NotifyOfPropertyChange(() => CanPrevious);
                NotifyOfPropertyChange(() => CanNext);
            }
        }

        private uint totalResults;
        public uint TotalResults
        {
            get { return totalResults; }
            set
            {
                totalResults = value;
                NotifyOfPropertyChange(() => TotalResults);
                NotifyOfPropertyChange(() => CanNext);
            }
        }

        private uint offset;
        public uint Offset
        {
            get { return offset; }
            set
            {
                offset = value;
                NotifyOfPropertyChange(() => Offset);
                NotifyOfPropertyChange(() => SearchResultText);
            }
        }

        public string SearchResultText
        {

            get
            {
                if (string.IsNullOrWhiteSpace(SearchText) && TotalResults == 0)
                    return string.Empty;

                long totalTemp = Offset + ItemsPerPage > TotalResults ? TotalResults : Offset + ItemsPerPage;

                var s = string.Format(Captions.SearchResultBaseText,
                    Offset + 1,
                    totalTemp,
                    TotalResults);

                return string.IsNullOrWhiteSpace(SearchText)
                           ? s
                           : string.Format(Captions.SearchTermBaseText, SearchText) + " " + s;
            }
        }

        #region Filters

        public IList<string> Sizes { get; private set; }
        public IList<string> Aspects { get; private set; }
        public IList<string> Colors { get; private set; }
        public IList<string> Styles { get; private set; }
        public IList<string> Faces { get; private set; }

        private string selectedSize;
        public string SelectedSize
        {
            get { return selectedSize; }
            set { selectedSize = value; NotifyOfPropertyChange(() => SelectedSize);}
        }

        private string selectedAspect;
        public string SelectedAspect
        {
            get { return selectedAspect; }
            set { selectedAspect = value; NotifyOfPropertyChange(() => SelectedAspect); }
        }

        private string selectedColor;
        public string SelectedColor
        {
            get { return selectedColor; }
            set { selectedColor = value; NotifyOfPropertyChange(() => SelectedColor); }
        }

        private string selectedStyle;
        public string SelectedStyle
        {
            get { return selectedStyle; }
            set { selectedStyle = value; NotifyOfPropertyChange(() => SelectedStyle); }
        }

        private string selectedFace;
        public string SelectedFace
        {
            get { return selectedFace; }
            set { selectedFace = value; NotifyOfPropertyChange(() => SelectedFace); }
        }

        #endregion

        #endregion

        #region Methods

        public IEnumerator<IResult> SearchItems()
        {
            Offset = 0;
            return Search();
        }

        public IEnumerator<IResult> SearchShortCut()
        {
            Offset = 0;
            return IsActive && CanSearchItems ? Search() : null;
        }

        private IEnumerator<IResult> Search()
        {
            yield return Show.Busy(this);

            var filters = ImageFilters.GetFilter(SelectedSize, SelectedAspect, SelectedColor, SelectedStyle, SelectedFace);

            yield return new ImageSearch(searchText, ItemsPerPage, Offset, filters, x =>
            {
                Results.Clear();
                if (x.Results != null)
                {
                    Results.AddRange(x.Results);
                    ItemsPerPage = (uint)x.Results.Length;
                }
                TotalResults = x.Total;
                Offset = x.Offset;
                CurrentPage = Offset / ItemsPerPage;
            }, x => eventAggregator.Publish(new ErrorMessage(x)));

            yield return Show.NotBusy(this);
        }

        public IEnumerator<IResult> Next()
        {
            Offset += ItemsPerPage;
            return Search();
        }

        public IEnumerator<IResult> Previous()
        {
            Offset -= ItemsPerPage;
            return Search();
        }

        public IEnumerator<IResult> Open()
        {
            if (SelectedItem == null)
                yield break;

            yield return Show.Busy(this);
            var uriSource = new Uri(SelectedItem.MediaUrl, UriKind.Absolute);
            yield return Show.Child<ShowPictureSingleViewModel>(SelectedItem.MediaUrl)
                .In(Parent)
                .Configured(x =>
                                {
                                    if (SelectedItem == null)
                                        return;
                                    x.WithPicture(uriSource, SelectedItem.Title); 
                                    SelectedItem = null;
                                });
            yield return Show.NotBusy(this);
            
        }

        #endregion
    }
}